#! /usr/bin/python
# -*- coding: utf-8 -*-
'''
Created on Jan 14, 2012

:author: JLucas Grillo (jlucas.gl@gmail.com)
:author: Juan José Fumero (jjfumero@gmail.com)


'''

import config_local
import os
import subprocess
import shutil
import stat

class Refactorization:

    def refactor(self, dir=config_local.WORKDIR, fromTo=None, extension = '.py', cuotes='"'):
        '''
            Refactor all python modules to import new public yacf modules
        '''
        print
        print " *** Refactorization of " + dir + " recursively ***"
        os.chdir(dir)
        print "Refactorizating " + dir + " ..."

        for s in fromTo:
            tmp = s[0].replace('.','\\.')
            print " Replacing \"" + tmp + cuotes + " whith " + cuotes + s[1] + "\" ...",
            subprocess.call("find -name '*" + extension + "' -exec sed -i -e " + cuotes + "s/" + 
                            tmp + "/" + s[1] + "/g" + cuotes + " '{}' \;",
                            shell=True)
            print "OK"
        print "OK"

    def writeFile(self, fileName, content):
        private = file(fileName, "w")
        private.write(content)

    def splitFileClass (self, dir=config_local.WORKDIR+'MiddleEnd/Loop/',
                        fileName='Analysis.py', privateClass='AccLoopParametrize'):
        ''' 
            This method separates the public and private classes of a mixed file
            Private classes are at the end of that file
        '''
        print
        print " *** Split", fileName, "file by", privateClass, "private class *** "
        print " Working on " + dir
        os.chdir(dir)
        print " Reading " + fileName + " ...",
        _file = file(fileName, "rU")
        fileString = ''.join(_file.readlines())
        print "OK"

        print " Writing backup file ...",
        self.writeFile(fileName + '.bak', fileString)
        print "OK"

        head = fileString.split('class')[0]
        privateClassDecl = 'class ' + privateClass

        # To private output file
        '''
        privateTail = privateClassDecl + fileString.split(privateClassDecl)[-1]
        privateHead = fileString.split('class')[0]
        self.writeFile(fileName + '.private', privateHead + privateTail)
        '''

        # To public file
        print " Extracting public file to " + fileName + " ...",
        publicContent = fileString.split(privateClassDecl)[0]
        self.writeFile(fileName, publicContent)
        #self.writeFile(fileName + '.public', publicContent)
        print "OK"

    def createPublicDirectories(self, dir=config_local.WORKDIR):
        '''
            Create public yacf directory and copy modules to it in right order
        '''
        print
        print " *** Create yacf public directories *** "
        os.chdir(dir)
        print "Working on ... " + config_local.WORKDIR

        if os.path.exists("./yacf"): shutil.rmtree("./yacf")

        print "Copying repository ...",
        shutil.copytree(".","./yacf", ignore=shutil.ignore_patterns('*.pyc'))
        print "OK"

        print "Creating yacf/ module ...",
        os.mkdir("./yacf/yacf/")
        file('./yacf/yacf/__init__.py', "w").close()
        print "OK"

        print "Copying public yacf module content ..."
        publicDirs = ["Frontend", "MiddleEnd", "Backends/C", "Backends/C99", "Backends/Common",
                         "Backends/DotBackend", "Tools", "utils", "doc", "examples", "Backends/MPI"]
        for d in publicDirs:
            print " yacf/" + d + " ...",
            shutil.copytree("./yacf/" + d, "./yacf/yacf/" + d)
            shutil.rmtree("./yacf/" + d)
            print "OK"
        
        file('./yacf/yacf/Backends/__init__.py', "w").close()

        shutil.rmtree("./yacf/Backends")

        print "Copying public drivers ..."
        shutil.rmtree("./yacf/bin/")
        os.mkdir("./yacf/bin/")
        publicDrivers = ["c2dependency_graph.py", "c2symbols.py", "c2tiling.py", "c2unroll.py", 
                         "c2unswitch.py", "c99acc.py", "index_analysis_test.py", "matrix2vect.py",
						 "c99.py", "c99omp.py", "spck.py", "c2mpi.py"
						]
        for f in publicDrivers:
            print " bin/" + f + " ...",
            shutil.copyfile("./bin/" + f, "./yacf/bin/" + f)
            print "ok"
        print "OK"   

        print "Public yacf repository generated."


    def generateSetup(self, dir=config_local.WORKDIR):

        print '\nWriting setup.py file ...........',
        content = """#!/usr/bin/python
# -*- coding: utf-8 -*-

import subprocess
import os
import re

## Generate config_local file
config_local = \"\"\" 
# Config file for llcomp

# Current work dir
WORKDIR="<dir>"


# Location of cuda files
CUDA_INSTALL_DIR="/usr/local/cuda/"

LEX_OPTIMIZE=True
YACC_OPTIMIZE=True
\"\"\"
print 'Writing config file ........ ',
pwd = os.getcwd()
config_local = re.sub("<dir>", pwd+'/', config_local)
fconfig = open('config_local.py', 'w')
fconfig.write(config_local)
fconfig.close()
print '[ok]'

# Generating AST
print 'Generating ast ......',
dir_config_frontend = "./yacf/Frontend/"
os.chdir(dir_config_frontend)
f = open("./loginstall",'w')
subprocess.call("python _ast_gen.py", shell=True, stdout=f)
print '[ok]'

# export PYTHONPATH
print 'Writing in bashrc ....',
export = "export PYTHONPATH=" + pwd + ":$PYTHONPATH"
subprocess.call(export, shell=True, stdout=f)
bashrc = open(os.environ['HOME']+'/.bashrc','a+')
bashrc.write(export)
bashrc.close()
print '[ok]'
        
        """
        fsetup = open(dir+'setup.py', 'w')
        fsetup.write(content)
        fsetup.close()
        print 'ok'

    def version(self):
        print
        repo = subprocess.Popen("hg path | grep default | awk -F' ' '{ print $3 }'", \
            stdout=subprocess.PIPE, shell=True).communicate()[0].split('\n')[0].split('/')[-1]
        print "   REPOSITORY: " + repo
        version = subprocess.Popen("hg tip | grep changeset", \
            stdout=subprocess.PIPE, shell=True).communicate()[0].split('\n')[0].split('changeset:')[1]
        print "   VERSION: " + version
        f = open(config_local.WORKDIR+'/yacf/VERSION','w')
        f.write("*************\n"+"Repository: "+repo+"\nChangeset: "+version+"\n*************\n")
        f.close()

if __name__ == '__main__':
    rtool = Refactorization()

    # Crea los directorios públicos
    rtool.createPublicDirectories(dir=config_local.WORKDIR)

    # Subdivide los ficheros que contienen código privado
    rtool.splitFileClass(dir=config_local.WORKDIR+'yacf/yacf/MiddleEnd/Loop/')
    os.remove(config_local.WORKDIR+'yacf/yacf/MiddleEnd/Loop/Analysis.py.bak')

    # Proceso de refactoización del módulo
    fromTo = [("from *MiddleEnd.", "from yacf.MiddleEnd."),
                  ("from *Backends.C99", "from yacf.Backends.C99"),
                  ("from *Backends.Common", "from yacf.Backends.Common"),
                  ("from *Backends.C.", "from yacf.Backends.C."),
                  ("from *Backends.DotBackend", "from yacf.Backends.DotBackend"),
                  ("from *Frontend", "from yacf.Frontend"),
                  ("'yacf.Frontend.", "'yacf.Frontend."),
                  ("from *Tools", "from yacf.Tools"),
                  ("'examples\/", "'yacf\/examples\/"),
                  ("FRONTEND_DIR = WORKDIR + '\/Frontend'", "FRONTEND_DIR = WORKDIR + 'yacf\/Frontend'"),
                  ("front *Backends.MPI", "from yacf.Backends.MPI")]
    rtool.refactor(config_local.WORKDIR + 'yacf/', fromTo, ".py")

    fromTo = [('FRONTEND_MODULE = "yacf.Frontend"', 'FRONTEND_MODULE = "yacf.Frontend"'),
                  ('"\/utils', '"\/yacf\/utils')]
    rtool.refactor(config_local.WORKDIR + 'yacf/', fromTo, ".py", "'")

    fromTo = [    ("MiddleEnd.", "yacf.MiddleEnd."),
                  ("`MiddleEnd", "`yacf.MiddleEnd"),
                  ("Backends.", "yacf.Backends."),
                  ("`Backends", "`yacf.Backends"),
                  ("Frontend.", "yacf.Frontend."),
                  ("`Frontend", "`yacf.Frontend"),
                  ("Tools.", "yacf.Tools."),
                  ("`Tools", "`yacf.Tools")]
    rtool.refactor(config_local.WORKDIR + 'yacf/yacf/doc/', fromTo, ".rst", '\'')
    rtool.generateSetup(config_local.WORKDIR+'/yacf/')

    # Se muestra información de la revisión
    rtool.version()

    # Mensaje final
    print
    print "Public yacf repository in: " + config_local.WORKDIR + 'yacf'
    print

    
